InputMangerService之Input事件分发流程

InputManagerService负责Android输入设备的事件管理,输入事件是Android应用程序最重要的组成部分,因此我们有必要对整个事件的流程进行分析。我们知道输入事件如触摸事件的分发流程是从view树的根部开始向下传递的,但本篇不对此进行分析,而是从事件发生的源头到该步所做的工作进行梳理。那么既然IMS最终要将事件投递到view树中,即DecorView对象上,那么可以想到IMS必然和WMS有不可分割的关系,其实,也可以想到,输入事件要被应用进行处理,必然投递到某一个前台窗口,后面我们会看到他们之间的紧密关系。

事件输入的流程启动

我们知道SystemServer在启动的时候会启动众多的系统服务,这些服务中就包括了WMS和IMS。下面我们看看他们分别是如何启动的。

frameworks/base/services/java/com/android/server/SystemServer.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void initAndLoop(){
……
// Create a handler thread just for the window manager to enjoy.
HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
wmHandlerThread.start();

//为WMS单独创建的HandlerThread
Handler wmHandler = new Handler(wmHandlerThread.getLooper());

……
//创建输入管理服务
inputManager = new InputManagerService(context, wmHandler);

Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, power, display, inputManager,
wmHandler, factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
!firstBoot, onlyCore);//创建WMS 同时这里将输入管理服务和其关联在一起
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

……
//为输入管理服务设置回调 这个回调来自WMS
inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
inputManager.start();//启动输入管理的流程

……
}

SystemServer进程在启动时会调用其Main方法进行一些初始化工作,initAndLoop就是在整个时候进行的,它会注册多个系统服务到Sm中去,这里我们关注WMS和IMS即可。
首先创建IMS的实例,并将其作为参数传递给WMS,随后将这两个服务的实例都加入到SM中

这里我们先看IMS的实例创建过程,它需要一个context和一个Handler作为参数来构造。这个Handler时为WMS创建的,这里传给IMS,说明他们之间共享这个Handler.

SystemServer中通过该构造方法创建IMS 注意这个handler是供WMS使用的,它里传过来说明它想和WMS共享handler

frameworks/base/services/java/com/android/server/input/InputManagerService.java

1
2
3
4
5
6
7
8
9
public InputManagerService(Context context, Handler handler) {
this.mContext = context;
this.mHandler = new InputManagerHandler(handler.getLooper());

mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
//创建native层的InputManager对象,结果保存在mPtr
}

IMS的构造很简单,它实际上调用natvieInit来创建native层的InputManger对象,对应于java层的IMS,结果返回给mPtr,注意这里的第三个参数为handler的MessageQueue.

frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//创建Native层的InputManager对象
static jint nativeInit(JNIEnv* env, jclass clazz,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}

NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());//直接看NativeInputManager的实现
im->incStrong(0);
return reinterpret_cast<jint>(im);
}

首先我们得到java层传进来的MessageQueue对象,然后通过它构造一个NativeInputManager对象,并返回给上层。我们接着看其构造

frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Native层的InputManger构造方法
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper) {
JNIEnv* env = jniEnv();

mContextObj = env->NewGlobalRef(contextObj);
mServiceObj = env->NewGlobalRef(serviceObj);

{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}

这里我们主要创建两个对象,一个EventHub对象,它是用来监听输入事件,也就是输入设备产生的Input事件。另一个对象为InputManager,它以eventHub对象作为其参数构造,这个InputMangager才是真正c++层的IMS服务,NativeInputManager只能算是一个壳,它持有InputMangaer的引用罢了,真正的事情应该是在InputManager中进行的。

frameworks/base/services/input/InputManager.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//c++层真正的IMS服务类
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//创建分派对象,用来分派Input事件 例如KeyEvent,MotionEvent
mDispatcher = new InputDispatcher(dispatcherPolicy);
//创建事件reader,这个是InputManger中的Input事件源,实际上它是通过eventHub得到事件的。
//同时,它和mDispatcher关联是因为需要将事件交给它来分派
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();//初始化
}

void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}

InputManager的构造方法做了三件事:

  1. 创建InputDispatcher对象,这个对象使用来分派Input事件的
  2. 创建InputReader对象,它的主要任务从EventHub读取事件并交给InputDispatcher处理,所里在其构造中我们可以看到eventHub和mDispatcher
  3. 初始化InputManger,分别为InputReader和InputDispatcher创建线程,InputManager的主要工作就是在这两个线程中完成的。

到这里InputManager就创建完成了,但它并没有开始工作,因为线程还未跑起来,其实在我们之前SystemServer可以看到,IMS在创建好实例后还需要关联上WMS,然后设置一个Window回调后才调用start启动工作。这个start流程会调用nativeStart进行native层的InputManager来启动真正的工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
status_t InputManager::start() {
status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}

result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
if (result) {
ALOGE("Could not start InputReader thread due to error %d.", result);

mDispatcherThread->requestExit();
return result;
}
return OK;
}

在InputManager的start中我们会启动初始化中创建的两个线程,分别用来处理读取Input事件和分派Input事件。接下来我们就从这两个线程的工作入手分析Input事件从下到上的整个流程。

输入事件在IMS中的分派

我们先看Reader线程的工作,它就是不断的通过mReader的loopOnce读取事件。所以具体的工作还是InputReader进行的,我们接下来就看InputReader的实现。

frameworks/base/services/input/InputReader.cpp

1
2
3
4
bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}

frameworks/base/services/input/InputReader.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);

{ // acquire lock
AutoMutex _l(mLock);

refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}

在InputReader的构造中我们传递了EventHub作为事件传递的源,还有InputDispatcher作为事件的分派者的listener,其中通过该listener构造了QueueInputListener对象,这个对象的用途后面我们再介绍。

frameworks/base/services/input/InputReader.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
Vector<InputDeviceInfo> inputDevices;
……
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();

if (count) {
processEventsLocked(mEventBuffer, count);
}

}
……
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
mQueuedListener->flush();
}

InputReader的线程的主要工作就是调用loopOnce,在这个方法中会通过我们在构造方法中传递的mEventHub对象来获取Input事件,结果保存在mEventBuffer,并返回count代表我们读取的事件数目,接着通过processEventsLocked进行处理,实际上这里会将读取的事件保存在一个缓冲队列中,最后调用mQueueListener的flush将事件发送出去。下面我们接着看着个流程。

frameworks/base/services/input/InputReader.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT
|| rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %d Count: %d", batchSize, count);
#endif
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}

我们看到事件消息一开始是作为一个RawEvent对象来根据其类型分别进行处理的,最基本的设备添加移除都通过专门的方法处理,其他事件都通过processEventsForDeviceLocked进行处理。至于addDeviceLocked,它是在添加输入设备时调用,用来添加输入设备的,在里面会对设备创建相应的InputDevice对象,同时创建会创建一些InputMapper,比如KeyboardInputMapper,TouchInputMapper等,这些InputMapper都保存在mMappers的列表中,后面我们会看到输入事件会交给这些mapper来进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void InputReader::processEventsForDeviceLocked(int32_t deviceId,
const RawEvent* rawEvents, size_t count) {
ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
if (deviceIndex < 0) {
ALOGW("Discarding event for unknown deviceId %d.", deviceId);
return;
}

InputDevice* device = mDevices.valueAt(deviceIndex);
if (device->isIgnored()) {
//ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}

device->process(rawEvents, count);
}

这一步我们通过mDevices取到对应的InputDevice,然后调用process进一步处理输入事件。

frameworks/base/services/input/InputReader.cpp

1
2
3
4
5
6
7
8
9
10
11
void InputDevice::process(const RawEvent* rawEvents, size_t count) {

if(){
……
} else {
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
mapper->process(rawEvent);
}
}
}

到这一步,input事件就交给Device,这里我们看看KeyboardInputMapper对键盘输入事件的处理。

frameworks/base/services/input/InputReader.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;

if (isKeyboardOrGamepadKey(scanCode)) {
int32_t keyCode;
uint32_t flags;
if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
keyCode = AKEYCODE_UNKNOWN;
flags = 0;
}
processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
}
break;
}
……
}
}

在process进一步调用processKey,表示处理按键事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
int32_t scanCode, uint32_t policyFlags) {

if (down) {
// Rotate key codes according to orientation if needed.
if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
keyCode = rotateKeyCode(keyCode, mOrientation);
}

// Add key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// key repeat, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
} else {
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL)
&& mContext->shouldDropVirtualKey(when,
getDevice(), keyCode, scanCode)) {
return;
}

mKeyDowns.push();
KeyDown& keyDown = mKeyDowns.editTop();
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
}

mDownTime = when;
} else {
// Remove key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// key up, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
mKeyDowns.removeAt(size_t(keyDownIndex));
} else {
// key was not actually down
ALOGI("Dropping key up from device %s because the key was not down. "
"keyCode=%d, scanCode=%d",
getDeviceName().string(), keyCode, scanCode);
return;
}
}

……
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
getListener()->notifyKey(&args);
}

这里首先对按键进行适当的处理,比如按键按下时,需要根据屏幕方向对按键的code进行旋转,这么做的原因可能是因为不同屏幕方向的key code表示的意义是不同的。还有如果对按下事件,如果已经存在了,就会发送持续的发送前一次的key code,否则就是按下事件,最后需要将key事件封装为一个NotifyKeyArgs参数,这些被封装的对象都是继承自NotifyArgs通过mQueuedListener,即QueuedInputListener的notifyKey分发这次Input消息。

frameworks/base/services/input/InputListener.cpp

1
2
3
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
mArgsQueue.push(new NotifyKeyArgs(*args));
}

这个NotifyKey只是将封装的事件参数添加到一个参数队列mArgsQueue中,真正的发送是在flush中进行,它是在loopOnce中的最后调用的表示要将事件派发出去了。

frameworks/base/services/input/InputListener.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}

void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}

在flush中实际上调用的是NotifyArgs的notify方法。在其方法中调用了Listener的notifyKey这个listener即 QueuedInputListener的mInnerListener,这个mInnerListener即是在创建QueuedInputListener时传递的参数InputDispatcher,这个就是我们的派发者对象。因为InputReader的主要任务就是将读取的Input事件交给InputDispatcher进行处理。

frameworks/base/services/input/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
……
bool needWake;
{ // acquire lock
mLock.lock();
……
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, args->keyCode, args->scanCode,
metaState, repeatCount, args->downTime);

needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock

if (needWake) {
mLooper->wake();
}
}

InputDipatcher通过notifyKey来处理InputReader交给的事件,这里通过事件参数args来构造一个KeyEntry对象,并通过enqueuInboundEventLocked将其加入到一个队列中去,等待进行处理,并根据needWake来决定唤醒Looper。

frameworks/base/services/input/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();

switch (entry->type) {
case EventEntry::TYPE_KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
KeyEntry* keyEntry = static_cast<KeyEntry*>(entry);
if (isAppSwitchKeyEventLocked(keyEntry)) {
if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
ALOGD("App switch is pending!");
#endif
mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
}
}
}
break;
}}}
return needWake;
}

enqueueInboundEventLocked将新的keyEvent加入到mInboundQueue中去,如果一开始这个队列是空的,就需要唤醒Looper了表示有新的事件需要处理。当事件到来后就会触发InputDipatcher的dispatchOnce,还记得?这个方法是在InputDipatcherThread的threadloop中循环调用进行事件处理的。我们看看它的具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();

// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}

// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock

// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}

这里事件的真正处理是在dispatchOnceInnerLocked中进行处理的。它会负责处理队列中的输入事件。然后通过pollOnce将事件发送出去,这是InputDispatcher的职责。下面我们看看dispatchOnceInnerLocked的具体实现。

frameworks/base/services/input/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
……
if (! mPendingEvent) {
if (mInboundQueue.isEmpty()) {
……
} else {
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
……
// Get ready to dispatch the event.
resetANRTimeoutsLocked();//重置ANR
}
switch (mPendingEvent->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
……
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
……
}

这个方法首先判断mInboundQueue队列是否有事件要处理,有的话就先取出队头的事件放到mPendingEvent中,根据事件类型分别进行处理,这里我们看类型为TYPE_KEY的输入事件。然后调用dispatchKeyLocked进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
……
// Identify targets.
Vector<InputTarget> inputTargets;
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}

setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}

addMonitoringTargetsLocked(inputTargets);

// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}

取出待处理的事件后通过dispatchKeyLocked进行处理,这个方法首先根据
findFocusedWindowTargetsLocked找到需要派发的目标对象inputTargets,然后通过
dispatchEventLocked进一步处理。

frameworks/base/services/input/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
……
for (size_t i = 0; i < inputTargets.size(); i++) {
const InputTarget& inputTarget = inputTargets.itemAt(i);

ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else { }
}
}

dispatchEventLocked方法主要是将待发送的输入事件发送给目标对象,这个目标对象是实际上为一个Connection,内部通过InputChannel构造,它是通过registerInputChannel中添加到一个mConnectionByFd的map中维护的。

1
2
3
4
5
6
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {

// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

prepareDispatchCycleLocked进一步调用enqueueDispatchEntriesLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();

// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
startDispatchCycleLocked(currentTime, connection);
}
}

再接着调用startDispatchCycleLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
……
while (connection->status == Connection::STATUS_NORMAL
&& !connection->outboundQueue.isEmpty()) {
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
dispatchEntry->deliveryTime = currentTime;

// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
keyEntry->deviceId, keyEntry->source,
dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
break;
}
……
}
……

// Re-enqueue the event on the wait queue.
connection->outboundQueue.dequeue(dispatchEntry);
traceOutboundQueueLengthLocked(connection);
connection->waitQueue.enqueueAtTail(dispatchEntry);
traceWaitQueueLengthLocked(connection);
}
}

到这里其实InputDispatcher的任务基本结束了,它已经将任务转给了具体的Connection进行处理,这个Connection即是再Dispatcher中注册的客户。下面我们分析这些Connection是如何注册到InputDispatcher的。这里我们从底层到上层追上去进行回顾整个流程
首先registerInputChannel是再NativeInputManager的registerInputChannel中调用的,而后者也应该是再Java层的InputManagerService中调用的,那么谁回去调用IMS的registerInputChannel呢?

InputChannel的注册

回顾我们之前再SystemServer中所做的事情,再IMS创建后会关联到WMS上,因为输入事件最终是要交给WMS负责分发给客户端的应用程序的。所以注册channel应该是再WMS上进行的。我们下来就看看这个注册的流程以及最终的事件是如何发布到上层的。首先我们去看那WMS的main方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static WindowManagerService main(final Context context,
final PowerManagerService pm, final DisplayManagerService dm,
final InputManagerService im, final Handler wmHandler,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
wmHandler.runWithScissors(new Runnable() {
@Override
public void run() {
holder[0] = new WindowManagerService(context, pm, dm, im,
haveInputMethods, showBootMsgs, onlyCore);//创建WMS实例
}
}, 0);
return holder[0];
}
```

Main主要负责创建WMS实例,所以我们看看其构造方法。

```java
private WindowManagerService(Context context, PowerManagerService pm,
DisplayManagerService displayManager, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
……
//WMS内部持有IMS的引用
mInputManager = inputManager; // Must be before createDisplayContentLocked.
……
}

在构造方法中实际上只是将IMS的实例保存在mInputManager中罢了,并没有任何注册的线索。那么注册的流程是在哪里呢?其实可以想象的到,当应用启动后,只有当界面显示出来的时候才能够接受输入事件,而且只有当前有焦点的窗口才可以对事件进行处理,而那些在任务栈中处于停止状态的窗口不对其进行处理。那么当窗口加入到WMS中时应该回去注册相应的channel用来接收事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
……
ViewRootImpl root;
View panelParentView = null;

synchronized (mLock) {

root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
root.setView(view, wparams, panelParentView);
……
}

这里我们主要看看ViewRootImpl的setView

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
……
//这次layout是为接受输入事件做准备,最重要的工作就是设置当前窗口为WMS中具 有焦点的窗口
requestLayout();
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
//为窗口创建一个Client端的InputChannel,它是用来监听Input事件的。
mInputChannel = new InputChannel();
}

try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
mInputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}

……
if (mInputChannel != null) {//前面为该window创建了InputChannel所以不为null
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();//创建一个InputQueue
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}
……
}

在setView中会去创建InputChannel,在这之前会调用一次requestLayout,这里的主要工作就是设置当前窗口为WMS中具有焦点的窗口,为接受输入事件做准备。那么这个InputChannel会去注册到InputDispatcher中?实际上不是的,注意这个方法还在我们的应用端。而接受InputDispather也就是IMS的输入事件的是WMS,那么事件的流程应该是IMS到WMS然后再到应用端程序。下面我们追踪mInputChannel来看看具体是怎么样的。

我们先看到mInputChannel,它的创建过程,它的构造方法是个空方法,这么说InputChannel现在在java层只是一个空壳,而真正的初始化是在native层的。接着我们看到mInputChannel被传递给了addToDisplay,这个方法将当前窗口添加到WMS中,它会通过Binder调用WMS的addWindow方法。所以我们去WMS中看看addWindow的实现

frameworks/base/services/java/com/android/server/wm/WindowManagerService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {

……
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);

mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
……
}

这里的outInputChannel就是我们客户端传递的mInputChannel,这里我们看到首先我们调用InputChannel的openInputChannelPair方法打开了一对InputChannel,这一对InputChannel分别是为Client和Server端的channel,用来负责应用端以及WMS的输入事件的接受通道。其中索引为0的为服务端的,而索引为1的为客户端的。我们看到inputChannels[0]先被保存在win中,也即是WindowState中,WindowState表示当前窗口,随后通过mInputManager调用registerInputChannel注册到InputDispatcher中。
而inputchanel[1]被转换为outInputChannel作为出参传递给应用端。这里我们先分析注册到InputDispatcher的这个InputChannel,随后再分析传递到客户端的inputchannel。

首先我们分析openInputChannelPair流程。

frameworks/base/core/java/android/view/InputChannel.java

1
2
3
4
5
6
7
8
9
10
public static InputChannel[] openInputChannelPair(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}

if (DEBUG) {
Slog.d(TAG, "Opening input channel pair '" + name + "'");
}
return nativeOpenInputChannelPair(name);
}

这个方法直接调用了native层的nativeOpenInputChannelPair方法

frameworks/base/core/jni/android_view_InputChannel.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);

sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

if (result) {
String8 message;
message.appendFormat("Could not open input channel pair. status=%d", result);
jniThrowRuntimeException(env, message.string());
return NULL;
}

jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
if (env->ExceptionCheck()) {
return NULL;
}

jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}

jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}

env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}

这个方法调用c++层的InputChannle(定义在InputTransport中)打开一对InputChannel对象,serverChannel和clientChannel,随后通过这两个对象调用android_view_input_channel_createInputChannel构造java层的InputChannel对象。

frameworks/native/libs/input/InputTransport.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.string(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}

int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName, sockets[0]);

String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}

首先通过socketpair创建一对相互连接的unnamed socket,这两个socket都可以互相进行读写,相比以前的管道通信,它是全双工的通信,即一端的socket既可以读又可以写。
创建好后,通过这两个socket分别去构造两个InputChannel作为服务端和客户端的读写通道。传递好后就可以将他们传递给java层使用了,这是通过android_view_input_channel_createInputChannel实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
NativeInputChannel* nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
}
return inputChannelObj;
}

static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
NativeInputChannel* nativeInputChannel) {
env->SetIntField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast<jint>(nativeInputChannel));
}

java层持有的其实是NativeInputChannel,它内部持有我们之前构造的InputChannel。
这个对象的地址会保存在java层的InputChannel的mPtr中。

创建好channel后接下来我们看看IMS是如何注册我们的服务端的InputChannel的
在之前addWindow中我们看到创建好Channel pair后就会调用IMS的registerInputChannel来注册服务端的Channel.

frameworks/base/services/java/com/android/server/input/InputManagerService.java

1
2
3
4
5
6
7
8
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}

nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}

frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp

1
2
3
4
5
6
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel(
inputChannel, inputWindowHandle, monitor);
}

这个mINputManager就是我们c++层的InputMnager,通过getDispatcher获取到的InputDispatcher对象就是我们在创建InputManger对象时创建的mDispatcher。

frameworks/base/services/input/InputDispatcher.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {

{ // acquire lock
AutoMutex _l(mLock);

if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}

sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);

int fd = inputChannel->getFd();
mConnectionsByFd.add(fd, connection);

if (monitor) {
mMonitoringChannels.push(inputChannel);
}

mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock

// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}

这里我们通过传递进来的InputChannel先创建一个Connection对象,随后添加到一个mConnectionsByFd这个Map中去。需要注意的是在注册完成之后会去为这个描述符注册回调handleReceiveCallBack中。

1
2
3
4
5
6
InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
monitor(monitor),
inputPublisher(inputChannel), inputPublisherBlocked(false) {
}

这里可以看到通过InputChannel构造一个InputPublisher对象,这个InputChannel是我们服务端的Channel,它最终是给WMS使用的。还记得?在InputDispater中正是通过它的publishKeyEvent方法来发布输入事件到WMS的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
status_t InputPublisher::publishKeyEvent(
uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
int32_t flags,
int32_t keyCode,
int32_t scanCode,
int32_t metaState,
int32_t repeatCount,
nsecs_t downTime,
nsecs_t eventTime) {

InputMessage msg;
msg.header.type = InputMessage::TYPE_KEY;
msg.body.key.seq = seq;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
return mChannel->sendMessage(&msg);
}

在publishKeyEvent中我们通过调用InputChannel的sendMessage将事件发送出去。

1
2
3
4
5
6
7
8
9
status_t InputChannel::sendMessage(const InputMessage* msg) {
size_t msgLength = msg->size();
ssize_t nWrite;
do {
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
……
return OK;
}

在sendMessage中实际上我们使用的是为WMS注册InputChannel来发送的事件消息,它的接收端位于我们应用程序的另一个InputChannel。接下来我们就需要看看应用程序是如何接受这个输入事件的。

应用端输入事件的接受

在WMS的addView中我们构造了一对InputChannel,其中一个作为服务端注册到了InputDispatcher中,另一个作为结果返回给了应用端,应用端正是使用这个InputChannel来监听输入事件的。

在ViewRootImpl的setView中调用了addToDisplay后就得到了这个InputChannel,随后又使用该InputChannel构造了一个一个WindowInputEvetnReceiver对象

1
2
3
4
5
6
7
8
if (mInputChannel != null) {//前面为该window创建了InputChannel所以不为null
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();//创建一个InputQueue
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());
}

这个WindowInputEventReceiver的实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}

@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}

@Override
public void onBatchedInputEventPending() {
scheduleConsumeBatchedInput();
}

@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}

从其实现来看它继承自InputEventReceiver,是用来接受输入事件的,其中onInputEvent重载了接受事件的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null");
}
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}

mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);

mCloseGuard.open("dispose");
}

这里的inputChannel是客户端使用的,它会通过nativeInit进行初始化,同时这个Looper是我们的主线程的Looper。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
jniThrowRuntimeException(env, "InputChannel is not initialized.");
return 0;
}

sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}

sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize input event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}

receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jint>(receiver.get());
}

nativeInit在native层创建对应的NativeInputEventReceiver对象,并调用了initialize进行初始化,同时将该native对象作为结果返回给java层的InputEventReceiver的mReceiverPtr成员。

1
2
3
4
5
6
7
8
9
10
11
12
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<InputChannel>& inputChannel,
const sp<MessageQueue>& messageQueue) :
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mInputConsumer(inputChannel), mMessageQueue(messageQueue),
mBatchedInputEventPending(false), mFdEvents(0) {
}

status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}

NativeInputEventReceiver的构造方法很简单,会通过inputchannel构造一个InputConsumer mInputConsumer,从名字来看它是一个输入事件的消费者,也就是我们客户端程序。

1
2
3
4
5
6
7
8
9
10
11
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}

这里将InputChannel的描述符fd取出来,然后通过主线程的Looper进行监听,当需要读取输入事件时会触发handleEVent回调。

1
2
3
4
5
6
7
8
9
10
11
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
……
if (events & ALOOPER_EVENT_INPUT) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, NULL);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
……
}

随后调用consumeEvents进一步对事件进行消费

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
……
ScopedLocalRef<jobject> receiverObj(env, NULL);
bool skipCallbacks = false;
for (;;) {
uint32_t seq;
InputEvent* inputEvent;
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
if (status) {
……
return status;
}
……
if (inputEventObj) {
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
env->DeleteLocalRef(inputEventObj);
} else {
ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
skipCallbacks = true;
}
}
……
}
}

这里先调用InputConsumer的consume方法进行事件的读取,随后通过gInputReceiverClassInfo的dispatchInputEvent方法发布到java层的InputEventReceiver

frameworks/native/libs/input/InputTransport.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
status_t InputConsumer::consume(InputEventFactoryInterface* factory,
bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {

*outSeq = 0;
*outEvent = NULL;

// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// Receive a fresh message.
status_t result = mChannel->receiveMessage(&mMsg);
……
}

switch (mMsg.header.type) {
case InputMessage::TYPE_KEY: {
KeyEvent* keyEvent = factory->createKeyEvent();
if (!keyEvent) return NO_MEMORY;

initializeKeyEvent(keyEvent, &mMsg);
*outSeq = mMsg.body.key.seq;
*outEvent = keyEvent;
break;
}
……
}
return OK;
}

这里首先通过Client端的InputChannel来读取服务发送的输入事件,然后将结果保存在outEvent中

frameworks/native/libs/input/InputTransport.cpp

1
2
3
4
5
6
7
8
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
……
return OK;
}

接下来就到java层看看我们如何接受输入事件的,刚才说过,输入事件最终是通过InputEventReceiver的dispatchInputEvent接受的。

1
2
3
4
5
6
// Called from native code.
@SuppressWarnings("unused")
private void dispatchInputEvent(int seq, InputEvent event) {
mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}

在dispatchInputEvent中是通过onInputEvent处理的,它真正的工作是它的子类WindowInputEventReceiver中进行处理的,它是在ViewRootImpl中定义的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}

@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}

@Override
public void onBatchedInputEventPending() {
scheduleConsumeBatchedInput();
}

@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}

void enqueueInputEvent(InputEvent event,
InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);

QueuedInputEvent last = mPendingInputEventTail;
if (last == null) {
mPendingInputEventHead = q;
mPendingInputEventTail = q;
} else {
last.mNext = q;
mPendingInputEventTail = q;
}
mPendingInputEventCount += 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);

if (processImmediately) {
doProcessInputEvents();
} else {
scheduleProcessInputEvents();
}
}

这里先将待处理的事件入队,并调用doProcessInputEvents进一步处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void doProcessInputEvents() {
// Deliver all pending input events in the queue.
while (mPendingInputEventHead != null) {
QueuedInputEvent q = mPendingInputEventHead;
mPendingInputEventHead = q.mNext;
if (mPendingInputEventHead == null) {
mPendingInputEventTail = null;
}
q.mNext = null;

mPendingInputEventCount -= 1;
Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
mPendingInputEventCount);

deliverInputEvent(q);
}

// We are done processing all input events that we can process right now
// so we can clear the pending flag immediately.
if (mProcessInputEventsScheduled) {
mProcessInputEventsScheduled = false;
mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
}
}

doProcessInputEvents的处理逻辑很简单,如果队列中有待处理的事件就循环调用deliverInputEvent进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void deliverInputEvent(QueuedInputEvent q) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "deliverInputEvent");
try {
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onInputEvent(q.mEvent, 0);
}

InputStage stage = q.shouldSkipIme() ? mFirstPostImeInputStage : mFirstInputStage;
if (stage != null) {
stage.deliver(q);
} else {
finishInputEvent(q);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}

public final void deliver(QueuedInputEvent q) {
if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {
forward(q);
} else if (shouldDropInputEvent(q)) {
finish(q, false);
} else {
apply(q, onProcess(q));
}
}

在deliverInputEvent中,事件被交给一个InputStage进行处理,这个InputState实际上是一个职责链,事件沿着职责链进行传递,当某个Stage需要处理的话就调用apply来调用onProcess进行事件的消费。这个职责链是在ViewRootImpl的setview中创建的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
InputStage syntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);

mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;

对于处理键盘输入事件,我们会交给viewPostImeStage进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
final class ViewPostImeInputStage extends InputStage {
public ViewPostImeInputStage(InputStage next) {
super(next);
}

@Override
protected int onProcess(QueuedInputEvent q) {
if (q.mEvent instanceof KeyEvent) {
return processKeyEvent(q);
} else {
// If delivering a new non-key event, make sure the window is
// now allowed to start updating.
handleDispatchDoneAnimating();
final int source = q.mEvent.getSource();
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
return processPointerEvent(q);
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
return processTrackballEvent(q);
} else {
//处理触摸事件
return processGenericMotionEvent(q);
}
}
}

private int processKeyEvent(QueuedInputEvent q) {
final KeyEvent event = (KeyEvent)q.mEvent;

if (event.getAction() != KeyEvent.ACTION_UP) {
// If delivering a new key event, make sure the window is
// now allowed to start updating.
handleDispatchDoneAnimating();
}

// Deliver the key to the view hierarchy.
if (mView.dispatchKeyEvent(event)) {
return FINISH_HANDLED;
}
……
}
return FORWARD;
}

private int processPointerEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;

if (mView.dispatchPointerEvent(event)) {
return FINISH_HANDLED;
}
return FORWARD;
}

……
private int processGenericMotionEvent(QueuedInputEvent q) {
final MotionEvent event = (MotionEvent)q.mEvent;

// Deliver the event to the view.
if (mView.dispatchGenericMotionEvent(event)) {
return FINISH_HANDLED;
}
return FORWARD;
}
}

在onProcess中如果事件类型为keyevent会交给processKeyEvent进行处理,后者会将事件投递给mView,即我们的DecorView,这样输入事件就可以view树上进行传递了。关于在view树中的处理流程,我们在另一篇中再做介绍。

坚持原创技术分享,您的支持将鼓励我继续创作!